package com.xuecheng.content.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xuecheng.api.content.model.dto.CourseBaseDTO;
import com.xuecheng.api.content.model.dto.TeachplanDTO;
import com.xuecheng.api.system.model.dto.CourseCategoryDTO;
import com.xuecheng.common.domain.code.CommonErrorCode;
import com.xuecheng.common.domain.response.RestResponse;
import com.xuecheng.common.enums.content.CourseAuditEnum;
import com.xuecheng.common.enums.content.CourseModeEnum;
import com.xuecheng.common.exception.ExceptionCast;
import com.xuecheng.common.util.JsonUtil;
import com.xuecheng.content.common.constant.ContentErrorCode;
import com.xuecheng.content.common.constant.CoursePubTemplateKey;
import com.xuecheng.content.convert.CourseBaseConvert;
import com.xuecheng.content.convert.CoursePub;
import com.xuecheng.content.entity.*;
import com.xuecheng.content.mapper.CourseBaseMapper;
import com.xuecheng.content.mapper.CoursePubMapper;
import com.xuecheng.content.service.*;
import com.xuecheng.feign.Client.SystemFeignClient;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.time.LocalDateTime;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 课程发布 服务实现类
 * </p>
 *
 * @author itcast
 */
@Slf4j
@Service
public class CoursePubServiceImpl extends ServiceImpl<CoursePubMapper, CoursePub> implements CoursePubService {
//    @Autowired
//    private CoursePubMapper coursePubMapper;
    @Autowired
    private CourseBaseService courseBaseService;

    @Autowired
    private CourseMarketService courseMarketService;

    @Autowired
    private TeachplanService teachplanService;

    @Autowired
    private CourseTeacherService courseTeacherService;

    @Autowired
    private SystemFeignClient systemFeignClient;


    @Override
    @Transactional
    public Map<String, Object> previewCourse(Long courseId, Long companyId) {
        /**
         *  0. 是否开启事务
         *  1. 判断关键数据
         *  2. 判断课程信息是否存在
         *  3.  生成宽表
         *  3。 生成dataMap集合 四个key组合
         */
//        1. 判断关键数据
        if(ObjectUtils.isEmpty(courseId)||
                ObjectUtils.isEmpty(companyId)){
            ExceptionCast.cast(CommonErrorCode.E_100101);
        }
//        判断课程信息是否存在
        CourseBaseDTO course = courseBaseService.getCourseById(courseId, companyId);

        if(ObjectUtils.isEmpty(course)){
            ExceptionCast.cast(ContentErrorCode.E_120013);
        }
        // 生成 宽表 coursePub
        CoursePub coursePub=generateCoursePub(courseId,companyId,false);

        // 生成 Map
        Map<String ,Object> map=generateDataMap(coursePub);

        return map;
    }

    private Map<String, Object> generateDataMap(CoursePub coursePub) {

        Map<String ,Object> map =new HashMap<>();

        map.put(CoursePubTemplateKey.COURSEPUB,coursePub);

        map.put(CoursePubTemplateKey.COURSEMARKET,JsonUtil.jsonToObject(coursePub.getMarket(),CourseMarket.class));

        CourseModeEnum[] values = CourseModeEnum.values();

        map.put(CoursePubTemplateKey.TEACHPLANNODE,JsonUtil.jsonToObject(coursePub.getTeachplan(), Teachplan.class));

//        String value = coursePub.getTeachmode();

        map.put(CoursePubTemplateKey.COURSETEACHMODEENUMS,values);

        // 课程教师

        String teachersJsonString = coursePub.getTeachers();

        List<CourseTeacher> teachers = JsonUtil.jsonToList(teachersJsonString, CourseTeacher.class);

        map.put("Teachers",teachers);


        return map;
    }


    private CoursePub generateCoursePub(Long courseId, Long companyId,boolean isPublih) {


//        基础课程信息放入
        CourseBaseDTO course = courseBaseService.getCourseById(courseId, companyId);
        String audit = course.getAuditStatus();
        // 已经发布
        if(isPublih){
            // 不是审核通过 就是异常
            if(!(CourseAuditEnum.AUDIT_PASTED_STATUS.getCode().equals(audit))){
                ExceptionCast.cast(ContentErrorCode.E_120015);
            }

        }else{
            if(audit.equals(CourseAuditEnum.AUDIT_PASTED_STATUS)||
                    audit.equals(CourseAuditEnum.AUDIT_COMMIT_STATUS)||
                    audit.equals(CourseAuditEnum.AUDIT_PUBLISHED_STATUS)
            ){
                ExceptionCast.cast(ContentErrorCode.E_120101);
            }

        }


        // 课程计划
        TeachplanDTO teachplanDTO = teachplanService.queryTreenodesByCourseId(courseId, companyId);
        String teachPlanJsonString = JsonUtil.objectTojson(teachplanDTO);

        // 课程营销
        LambdaQueryWrapper<CourseMarket> marketLambdaQueryWrapper = new LambdaQueryWrapper<>();
        marketLambdaQueryWrapper.eq(CourseMarket::getCourseId,courseId);
        CourseMarket market = courseMarketService.getOne(marketLambdaQueryWrapper);
        if(ObjectUtils.isEmpty(market)){
            ExceptionCast.cast(ContentErrorCode.E_120101);
        }
        String marketJsonString  = JsonUtil.objectTojson(market);

        // 课程分类
        String st = course.getSt();
        String mt = course.getMt();

        RestResponse<CourseCategoryDTO> mtResponse = systemFeignClient.getById(mt);
        if(!mtResponse.isSuccessful()){
            ExceptionCast.castWithCodeAndDesc(mtResponse.getCode(),mtResponse.getMsg());
        }
        CourseCategoryDTO mtCategory = mtResponse.getResult();
        String mtName = mtCategory.getName();


        RestResponse<CourseCategoryDTO> stResponse = systemFeignClient.getById(st);
        if(!stResponse.isSuccessful()){
            ExceptionCast.castWithCodeAndDesc(stResponse.getCode(),stResponse.getMsg());
        }
        CourseCategoryDTO stCategory = stResponse.getResult();
        String stName = stCategory.getName();

        // 课程老师信息
        LambdaQueryWrapper<CourseTeacher> teacherLambdaQueryWrapper = new LambdaQueryWrapper<>();
        teacherLambdaQueryWrapper.eq(CourseTeacher::getCourseId,courseId);
        List<CourseTeacher> courseTeachers = courseTeacherService.list(teacherLambdaQueryWrapper);

        String teacherJsonString=null;
        if(!CollectionUtils.isEmpty(courseTeachers)){
             teacherJsonString = JsonUtil.objectTojson(courseTeachers);
        }

// 组装

        CoursePub coursePub= CourseBaseConvert.INSTANCE.course2coursePub(course);
        coursePub.setTeachplan(teachPlanJsonString);
        coursePub.setMarket(marketJsonString);
        coursePub.setTeachers(teacherJsonString);

        // 增加冗余字段
        coursePub.setPrice(market.getPrice());
        coursePub.setCharge(market.getCharge());


        // 课程分类名称完善
        coursePub.setStName(stName);
        coursePub.setMtName(mtName);

        // 关联 课程id
        coursePub.setCourseId(courseId);

        LambdaQueryWrapper<CoursePub> queryWrapper = new LambdaQueryWrapper<>();

        queryWrapper.eq(CoursePub::getCourseId,courseId);

        CoursePub po = this.getOne(queryWrapper);
        boolean result=false;
        if(ObjectUtils.isEmpty(po)){
            result = this.save(coursePub);
        }else{
            coursePub.setId(po.getId());
            result=this.updateById(coursePub);
        }

        if(!result){
            ExceptionCast.cast(ContentErrorCode.E_120205);
        }


        return coursePub;
    }



    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired
    private CoursePubMsgService coursePubMsgService;
    @Value("${course.publish.exchange}")
    private String exchange;
    @Value("${course.publish.routingkey}")
    private String routingkey;


    @Transactional
    public void publish(Long courseBaseId, Long companyId, boolean isReSend) {
        /*
         * 构建CoursePub数据并保存
         *   业务分析：
         *       1.判断关键数据
         *        courseId companyId
         *       2.判断业务数据
         *           课程基础信息
         *               判断是否存在
         *               判断是否是同一家机构
         *               判断是否删除
         *               判断审核状态：教学机构课程预览--未提交、审核未通过
         *           课程营销
         *               判断是否存在：根据courseid
         *           课程计划
         *               获得课程计划：根据courseId和companyId（树形结构）
         *           课程教师
         *               判断教师信息是否存在：一定要确保课程最少有一个教师信息
         *
         *           课程分类数据并完善Coursepub数据
         *               调用system服务获得课程分类的名称
         *
         *       3.保存数据的业务数据和消息数据
         *           业务数据：CoursePub数据进行保存
         *           消息数据：CoursePubMsg数据进行保存
         *
         *       4.发送消息给MQ
         *
         * */
//        1.判断关键数据
//        courseId companyId
        if(ObjectUtils.isEmpty(courseBaseId)||ObjectUtils.isEmpty(companyId)||ObjectUtils.isEmpty(isReSend)){
            ExceptionCast.cast(CommonErrorCode.E_100101);
        }

//        2.判断业务数据
//                课程基础信息
//        判断是否存在
//                判断是否是同一家机构
//        判断是否删除
//        判断审核状态：教学机构课程预览--未提交、审核未通过
//                课程营销
//        判断是否存在：根据courseid
//                课程计划
//        获得课程计划：根据courseId和companyId（树形结构）
//        课程教师
//        判断教师信息是否存在：一定要确保课程最少有一个教师信息
//                课程分类数据并完善Coursepub数据
//        调用system服务获得课程分类的名称


        //        3.保存数据的业务数据和消息数据
//        业务数据：CoursePub数据进行保存

//        消息数据：CoursePubMsg数据进行保存
         // 审核通过

        // 如果是重发，就直接查到当前的发布状态表的当前字段
        // 如果不是重发， 就新建新建发布信息，新建发布状态表信息
        CoursePubMsg coursePubMsg=null;
        // 存在就直接取出来
        if(isReSend){
            LambdaQueryWrapper<CoursePubMsg> coursePubMsgLambdaQueryWrapper = new LambdaQueryWrapper<>();
            coursePubMsgLambdaQueryWrapper.eq(CoursePubMsg::getCourseId,courseBaseId);
             coursePubMsg = coursePubMsgService.getOne(coursePubMsgLambdaQueryWrapper);
        }else {  // 不是重发，就新建一个

            CoursePub coursePub = generateCoursePub(courseBaseId, companyId,true);
            // 空的就存一个
//            if (ObjectUtils.isEmpty(coursePubMsg)) {

                coursePubMsg = CoursePubMsg.builder().courseId(coursePub.getCourseId())
                        .pubId(coursePub.getId())
                        .pubStatus(CoursePubMsg.UNSENT)
                        .pubName(coursePub.getName())
                        .companyId(coursePub.getCompanyId())
                        .build();

                boolean result = coursePubMsgService.save(coursePubMsg);
                if (!result) {
                    ExceptionCast.cast(ContentErrorCode.E_120202);
                }
//            } else {
//                // 如果有：消息存在，不要再次发送消息  // 不用保存
//                return;
//            }

        }


//        4.发送消息给MQ

        CorrelationData correlationData = new CorrelationData(coursePubMsg.getPubId().toString());

        correlationData.getFuture().addCallback(
                confirm -> {
                    if (confirm.isAck()) {
                        executeChangeLocalStatusData(correlationData.getId());
                    } else {
                        log.error("mq交换机接受消息失败，消息id ：{} ",correlationData.getId());
                    }
                },
                throwable -> {
                    log.error("消息发送失败，mq服务异常，消息的id：{} ，errormsg：{}",correlationData.getId(),
                            throwable.getMessage());

                }

        );
        //  找到交换机，可以发消息
        String jsonString = JsonUtil.objectTojson(coursePubMsg);

        rabbitTemplate.convertAndSend(exchange,routingkey,jsonString,correlationData);
    }
    // 改变本地状态表的状态
    private void executeChangeLocalStatusData(String coursePubIdStr) {

        //1.修改课程发布消息表数据
        //    未发送-->已发送
        Long coursePubId = new Long(coursePubIdStr);
        LambdaUpdateWrapper<CoursePubMsg> pubMsgUpdateWrapper = new LambdaUpdateWrapper<>();
        pubMsgUpdateWrapper.set(CoursePubMsg::getPubStatus, CoursePubMsg.SENT);
        pubMsgUpdateWrapper.set(CoursePubMsg::getChangeDate, LocalDateTime.now());
        pubMsgUpdateWrapper.eq(CoursePubMsg::getPubId, coursePubId);

        coursePubMsgService.update(pubMsgUpdateWrapper);

        // 修改课程基本信息表的审核状态为已发布
        CoursePubMsg coursePubMsg = coursePubMsgService.getById(coursePubId);
        LambdaUpdateWrapper<CourseBase> baseUpdateWrapper = new LambdaUpdateWrapper<>();
        baseUpdateWrapper.set(CourseBase::getAuditStatus, CourseAuditEnum.AUDIT_PUBLISHED_STATUS.getCode());
        baseUpdateWrapper.set(CourseBase::getChangeDate, LocalDateTime.now());
        baseUpdateWrapper.eq(CourseBase::getId, coursePubMsg.getCourseId());

        courseBaseService.update(baseUpdateWrapper);
    }
}
